package com.nmp.model;

import business.service.MongoDbFactory;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.nmp.common.CommonUtil;
import com.nmp.common.UserData;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import org.bson.types.ObjectId;

/**
 *
 * @author vietph
 */
public class UserModel {

    private static final String USER_COLLECTION = "users";
    private static final String USER_INFO_COLLECTION = "users_info";

    private static UserModel instance = null;
    private static final Lock iLock = new ReentrantLock();
    protected final Logger logger = Logger.getLogger(this.getClass());

    public static UserModel getInstance() {
        iLock.lock();
        try {
            if (instance == null) {
                instance = new UserModel();
            }
            return instance;
        } finally {
            iLock.unlock();
        }
    }

    public UserModel() {
        try {
        } catch (Exception e) {
            logger.error("UserModel.constructor: " + e.getMessage());
        }
    }

    public UserData getUserByEmail(String email) {
        UserData userData = getUserAccountByEmail(email, null);
        userData = getUserInfoById(userData.getId(), userData);
        
        return userData;
    }

    public UserData getUserById(String id) {
        UserData userData = getUserAccountById(id, null);
        userData = getUserInfoById(id, userData);
        
        return userData;
    }
    
    public UserData getUserByAppUserId(String app_user_id) {
        UserData userData = getUserInfoByAppUserId(app_user_id, null);
        if(userData != null)
            userData = getUserAccountById(userData.getId(), userData);
        
        return userData;
    }
    
    private UserData getUserAccountByEmail(String email, UserData userData) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject("email", email);
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String id = ((ObjectId) dbObject.get("_id")).toString();
                long created = (long) dbObject.get("created");
                if(userData == null)
                    userData = new UserData(id, "", email, "", created);
                else {
                    userData.setId(id);
                    userData.setEmail(email);
                    userData.setPasswdMD5("");
                    userData.setCreated(created);
                }
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUserByEmail: " + ex.getMessage(), ex);
        }
        return userData;
    }
    
    private UserData getUserAccountById(String id, UserData userData) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject("_id", new ObjectId(id));
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String email = (String) dbObject.get("email");
                long created = (long) dbObject.get("created");
                if(userData == null)
                    userData = new UserData(id, "", email, "", created);
                else {
                    userData.setId(id);
                    userData.setEmail(email);
                    userData.setPasswdMD5("");
                    userData.setCreated(created);
                }
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUserByEmail: " + ex.getMessage(), ex);
        }
        return userData;
    }
    
    private UserData getUserInfoById(String id, UserData userData) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject("account_id", new ObjectId(id));
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_INFO_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String app = (String) dbObject.get("app");
                String app_user_id = (String) dbObject.get("app_user_id");
                String avatar = (String) dbObject.get("avatar");
                String name = (String) dbObject.get("name");
                int gender = (int) dbObject.get("gender");
                long dob = (long) dbObject.get("dob");
                String link = (String) dbObject.get("link");
                if(userData == null)
                    userData = new UserData(id, app, app_user_id, avatar, name, gender, dob, link);
                else {
                    userData.setApp(app);
                    userData.setApp_user_id(app_user_id);
                    userData.setAvatar(avatar);
                    userData.setName(name);
                    userData.setGender(gender);
                    userData.setDob(dob);
                }
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUserByEmail: " + ex.getMessage(), ex);
        }
        return userData;
    }
    
    private UserData getUserInfoByAppUserId(String app_user_id, UserData userData) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject("app_user_id", app_user_id);
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_INFO_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String id = ((ObjectId) dbObject.get("account_id")).toString();
                String app = (String) dbObject.get("app");
                String avatar = (String) dbObject.get("avatar");
                String name = (String) dbObject.get("name");
                int gender = (int) dbObject.get("gender");
                long dob = (long) dbObject.get("dob");
                String link = (String) dbObject.get("link");
                if(userData == null)
                    userData = new UserData(id, app, app_user_id, avatar, name, gender, dob, link);
                else {
                    userData.setId(id);
                    userData.setApp(app);
                    userData.setApp_user_id(app_user_id);
                    userData.setAvatar(avatar);
                    userData.setName(name);
                    userData.setGender(gender);
                    userData.setDob(dob);
                }
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUserInfoByAppUserId: " + ex.getMessage(), ex);
        }
        return userData;
    }
    
    public String addUser(UserData userData) {
        boolean isExistEmail = checkEmailExist(userData.getEmail());
        String accId;
        if(!isExistEmail) {
            accId = addUserAccount(userData);
        } else {
            userData = getUserAccountByEmail(userData.getEmail(), userData);
            accId = userData.getId();
        }
        addUserInfo(accId, userData);
        
        return accId;
    }
    
    private String addUserAccount(UserData userData) {
        String id = "";
        try {
            BasicDBObject basicDBObject = new BasicDBObject()
                    .append("email", userData.getEmail())
                    .append("pass", userData.getPasswdMD5())
                    .append("created", userData.getCreated());

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            coll.insert(basicDBObject);

            ObjectId objectId = (ObjectId) basicDBObject.get("_id");
            id = objectId.toString();
        } catch (Exception ex) {
            logger.error("UserModel.addUserAccount: " + ex.getMessage());
        }
        return id;
    }
    
    private String addUserInfo(String accId, UserData userData) {
        String id = "";
        try {
            BasicDBObject basicDBObject = new BasicDBObject()
                    .append("account_id", new ObjectId(accId))
                    .append("app", userData.getApp())
                    .append("app_user_id", userData.getApp_user_id())
                    .append("avatar", userData.getAvatar())
                    .append("name", userData.getName())
                    .append("gender", userData.getGender())
                    .append("dob", userData.getDob())
                    .append("link", userData.getLink())
                    .append("created", userData.getCreated());

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_INFO_COLLECTION);
            coll.insert(basicDBObject);

            ObjectId objectId = (ObjectId) basicDBObject.get("_id");
            id = objectId.toString();
        } catch (Exception ex) {
            logger.error("UserModel.addUserInfo: " + ex.getMessage());
        }
        return id;
    }

    public boolean deleteUser(String id) {
        try {
            DB db = MongoDbFactory.getConnection();
            DBCollection collAcc = db.getCollection(USER_COLLECTION);
            collAcc.remove(new BasicDBObject("_id", new ObjectId(id)));
            
            DBCollection collInfo = db.getCollection(USER_INFO_COLLECTION);
            collInfo.remove(new BasicDBObject("account_id", new ObjectId(id)));

            return true;
        } catch (Exception ex) {
            logger.error("UserModel.deleteUser: " + ex.getMessage(), ex);
        }
        return false;
    }

    public boolean updateUserPass(UserData userData) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject()
                    .append("pass", userData.getPasswdMD5());

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);

            BasicDBObject updateDBObject = new BasicDBObject("$set", basicDBObject);
            BasicDBObject searchDBQuery = new BasicDBObject("_id", new ObjectId(userData.getId()));
            coll.update(searchDBQuery, updateDBObject);
            return true;
        } catch (Exception ex) {
            logger.error("UserModel.updateUserPass: " + ex.getMessage());
        }
        return false;
    }

    public List<UserData> getUser(int start, int limit) {
        List<UserData> lstUser = null;
        try {
            BasicDBObject basicDBObject = new BasicDBObject("_id", -1);
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find().sort(basicDBObject);
            if (limit != -1) {
                cursor = cursor.skip(start).limit(limit);
            }
            lstUser = new ArrayList<>();
            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String id = ((ObjectId) dbObject.get("_id")).toString();
                String email = (String) dbObject.get("email");
                long created = (long) dbObject.get("created");

                UserData userData = new UserData(id, "", email, "", created);
                userData = getUserInfoById(id, userData);
                
                lstUser.add(userData);
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUser: " + ex.getMessage(), ex);
        }
        return lstUser;
    }

    public long getTotalUser() {
        long count = 0;
        try {
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            count = coll.getCount();
        } catch (Exception ex) {
            logger.error("UserModel.getTotalUser: " + ex.getMessage(), ex);
        }
        return count;
    }

    public String validateUser(String email, String password) {
        String id = "";
        try {
            email = email.toLowerCase();
            password = CommonUtil.md5(password);

            BasicDBObject basicDBObject = new BasicDBObject("email", email)
                    .append("pass", password);

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                id = ((ObjectId) dbObject.get("_id")).toString();
            }
        } catch (Exception ex) {
            logger.error("UserModel.validateUser: " + ex.getMessage(), ex);
        }
        return id;
    }
    
    public boolean checkEmailExist(String email) {
        try {
            if(email == null)
                return false;
            email = email.toLowerCase();
            BasicDBObject basicDBObject = new BasicDBObject("email", email);

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                return true;
            }
        } catch (Exception ex) {
            logger.error("UserModel.checkEmailExist: " + ex.getMessage(), ex);
        }
        return false;
    }
    
    public boolean checkAppUserExist(String app_user_id) {
        try {
            if(app_user_id == null)
                return false;
            BasicDBObject basicDBObject = new BasicDBObject("app_user_id", app_user_id);

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_INFO_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                return true;
            }
        } catch (Exception ex) {
            logger.error("UserModel.checkAppUserExist: " + ex.getMessage(), ex);
        }
        return false;
    }
}
